﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.IO;

namespace DBMS.Indexes.Tree.BPlus
{
    public class Tree<IT, OT>
    {
        private int order;
        private Node<IT> root;


        public Tree(int order, String tablePath)
        {
            this.order = order;
            foreach (String filePath in Directory.GetFiles(tablePath, "V_"))
            {
                //
            }
        }


        public OT GetData(ComparableIndex<IT> soughtItem)
        {
            LeafNode<IT, OT> result = SearchPlace(soughtItem);
            for (int i = 0; i < result.NrItems; i++)
            {
                if (result.GetKey(i).isEqualWith(soughtItem))
                {
                    return result.GetDataPointer(i);
                }
            }
            throw new Exception("Not Found" + soughtItem);
        }


        public LeafNode<IT, OT> SearchPlace(ComparableIndex<IT> soughtItem)
        {
            Node<IT> node = root;
            int i = 0;
            bool found;

            while (node is InternalNode<IT>)
            {
                InternalNode<IT> internalNode = (InternalNode<IT>)node;
                i = 0;
                found = false;
                ComparableIndex<IT> item;

                while((i < order) && (!found)) 
                {
                    item = internalNode.GetKey(i);
                    if (soughtItem.lessThanOrEqual(item))
                    {
                        node = internalNode.GetNodePointer(i);
                        found = true;
                    }
                    else
                    {
                        i++;
                    }
                }

                if (!found)
                {
                    node = internalNode.GetNodePointer(i);
                }
            }

            if (node == null)
            {
                node = new LeafNode<IT, OT>(order);
            }
            return (LeafNode<IT, OT>)node;
        }


        public bool Insert(ComparableIndex<IT> index, Object pointer)
        {
            Node<IT> node = SearchPlace(index);
            if (!node.IsFull())
            {
                node.AddKey(index, pointer);
                if (root == null)
                {
                    root = node;
                }
            }
            else
            {
                Node<IT> newNode = node.Split(index, pointer);
                InsertToParent(node, node.GetKey(0), newNode);
            }
            return true;
        }

        public void InsertToParent(Node<IT> child, ComparableIndex<IT> index, Node<IT> pointer)
        {
            Node<IT> parentNode = GetParentNode(child);
            if (parentNode == null)
            {
                parentNode = new InternalNode<IT>(order);
                root = parentNode;
                root.InfinityPointer = child;
            }

            if (!parentNode.IsFull())
            {
                parentNode.AddKey(index, pointer);
            }
            else
            {
                Node<IT> newNode = parentNode.Split(index, pointer);
                InsertToParent(parentNode, newNode.GetKey(0), newNode);
            }
        }


        public Node<IT> GetParentNode(Node<IT> child) 
        {
            return null;
        }


        private Node<IT> SearchParentNode(Node<IT> start, Node<IT> child)
        {
            Node<IT> result = null;
            Node<IT> parent = null;
            Object pointer = null;
            for (int i = 0; i < start.NrItems; i++)
            {
                pointer = start.GetPointer(i);
                if(pointer is Node<IT>) 
                {
                    parent = (Node<IT>)pointer;
                    if (parent == child)
                    {
                        return parent;
                    }
                    result = SearchParentNode(parent, child);
                    if (result != null)
                    {
                        return result;
                    }
                }
            }
            return result;
        }
    }
}